package cn.cdutetc.library.service.impl;

import cn.cdutetc.library.entity.dto.FeeVO;
import cn.cdutetc.library.entity.dto.FeeRecordVO;
import cn.cdutetc.library.entity.dto.FeeStatisticsVO;
import cn.cdutetc.library.entity.pojo.Book;
import cn.cdutetc.library.entity.pojo.BorrowRecord;
import cn.cdutetc.library.entity.pojo.FeeRecord;
import cn.cdutetc.library.entity.pojo.User;
import cn.cdutetc.library.common.exception.BizException;
import cn.cdutetc.library.mapper.BookMapper;
import cn.cdutetc.library.mapper.BorrowRecordMapper;
import cn.cdutetc.library.mapper.FeeRecordMapper;
import cn.cdutetc.library.mapper.UserMapper;
import cn.cdutetc.library.service.FeeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 费用服务实现类
 */
@Service
public class FeeServiceImpl implements FeeService {

    // 逾期罚款每天金额（元）
    private static final BigDecimal OVERDUE_DAILY_FEE = new BigDecimal("0.5");

    @Autowired
    private BorrowRecordMapper borrowRecordMapper;

    @Autowired
    private BookMapper bookMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private FeeRecordMapper feeRecordMapper;

    /**
     * 计算逾期罚款
     */
    @Override
    @Transactional
    public FeeVO calculateOverdueFee(Integer userId) {
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BizException("用户不存在");
        }

        // 查询用户所有逾期未还的借阅记录
        LambdaQueryWrapper<BorrowRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BorrowRecord::getUserId, userId)
                .eq(BorrowRecord::getStatus, "overdue");
        List<BorrowRecord> overdueBorrows = borrowRecordMapper.selectList(queryWrapper);

        if (overdueBorrows.isEmpty()) {
            // 没有逾期记录
            FeeVO feeVO = new FeeVO();
            feeVO.setUserId(userId);
            feeVO.setUserName(user.getUsername());
            feeVO.setType("overdue_fee");
            feeVO.setTypeDesc("逾期罚款");
            feeVO.setAmount(BigDecimal.ZERO);
            feeVO.setCalculateTime(LocalDateTime.now());
            return feeVO;
        }

        // 计算总逾期费用并检查/创建记录
        BigDecimal totalOverdueFee = BigDecimal.ZERO;
        boolean hasNewRecord = false;

        for (BorrowRecord borrow : overdueBorrows) {
            // 计算逾期天数
            long days = ChronoUnit.DAYS.between(borrow.getDueDate(), LocalDateTime.now());
            if (days <= 0) {
                continue; // 不应出现这种情况，但做安全处理
            }

            // 计算单本图书逾期费用
            BigDecimal bookFee = OVERDUE_DAILY_FEE.multiply(new BigDecimal(days));
            totalOverdueFee = totalOverdueFee.add(bookFee);

            // 检查是否已有该借阅记录的逾期罚款 - 使用long接收
            long existingCount = countExistingFee(userId, borrow.getRecordId(), "overdue_fee");

            if (existingCount == 0) {
                // 不存在则创建新记录
                createOverdueFeeRecord(user, borrow, days, bookFee);
                hasNewRecord = true;
            }
        }

        // 构建返回结果
        FeeVO feeVO = new FeeVO();
        feeVO.setUserId(userId);
        feeVO.setUserName(user.getUsername());
        feeVO.setType("overdue_fee");
        feeVO.setTypeDesc("逾期罚款");
        feeVO.setAmount(totalOverdueFee.setScale(2, RoundingMode.HALF_UP));
        feeVO.setCalculateTime(LocalDateTime.now());

        // 如果有新增记录，查询最新创建的记录ID
        if (hasNewRecord) {
            LambdaQueryWrapper<FeeRecord> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(FeeRecord::getUserId, userId)
                    .eq(FeeRecord::getFeeType, "overdue_fee")
                    .orderByDesc(FeeRecord::getCreateTime)
                    .last("LIMIT 1");
            FeeRecord latestRecord = feeRecordMapper.selectOne(wrapper);
            if (latestRecord != null) {
                feeVO.setFeeId(latestRecord.getFeeId());
            }
        }

        return feeVO;
    }

    /**
     * 计算损坏赔偿费用
     */
    @Override
    @Transactional
    public FeeVO calculateDamageFee(Integer userId, Integer bookId, double damageRatio) {
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BizException("用户不存在");
        }

        // 检查图书是否存在
        Book book = bookMapper.selectById(bookId);
        if (book == null) {
            throw new BizException("图书不存在");
        }

        // 验证损坏比例有效性
        if (damageRatio <= 0 || damageRatio > 2) {
            throw new BizException("损坏赔偿比例必须在0到2之间");
        }

        // 查找用户是否有该图书的借阅记录
        Integer recordId = findUserBookBorrowRecord(userId, bookId);

        // 检查是否已有损坏赔偿记录 - 使用long接收
        long existingCount = countExistingFee(userId, recordId, "damage_fee");
        if (existingCount > 0) {
            // 已有记录，返回该记录信息
            LambdaQueryWrapper<FeeRecord> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(FeeRecord::getUserId, userId)
                    .eq(FeeRecord::getFeeType, "damage_fee")
                    .orderByDesc(FeeRecord::getCreateTime)
                    .last("LIMIT 1");

            // 如果有借阅记录ID，添加到查询条件中
            if (recordId != null) {
                wrapper.eq(FeeRecord::getRecordId, recordId);
            } else {
                wrapper.isNull(FeeRecord::getRecordId);
            }

            FeeRecord existingRecord = feeRecordMapper.selectOne(wrapper);

            // 增加空指针检查
            if (existingRecord == null) {
                throw new BizException("系统检测到已有赔偿记录，但无法获取详情，请联系管理员");
            }

            FeeVO feeVO = createDamageFeeVO(user, book, damageRatio, existingRecord.getAmount());
            feeVO.setFeeId(existingRecord.getFeeId());
            return feeVO;
        }

        // 计算损坏赔偿费用
        BigDecimal damageFee = book.getPrice().multiply(new BigDecimal(damageRatio))
                .setScale(2, RoundingMode.HALF_UP);

        // 创建损坏赔偿记录
        FeeRecord feeRecord = new FeeRecord();
        feeRecord.setUserId(userId);
        feeRecord.setRecordId(recordId);
        feeRecord.setFeeType("damage_fee");
        feeRecord.setAmount(damageFee);
        feeRecord.setStatus("unpaid");
        feeRecord.setCreateTime(LocalDateTime.now());
        feeRecord.setRemark(String.format("用户%d损坏《%s》，按%.2f比例赔偿",
                userId, book.getBookName(), damageRatio));

        feeRecordMapper.insert(feeRecord);

        // 构建并返回结果
        FeeVO feeVO = createDamageFeeVO(user, book, damageRatio, damageFee);
        feeVO.setFeeId(feeRecord.getFeeId());

        return feeVO;
    }

    /**
     * 计算丢失赔偿费用
     */
    @Override
    @Transactional
    public FeeVO calculateLostFee(Integer userId, Integer bookId, double lostRatio) {
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BizException("用户不存在");
        }

        // 检查图书是否存在
        Book book = bookMapper.selectById(bookId);
        if (book == null) {
            throw new BizException("图书不存在");
        }

        // 验证丢失比例有效性
        if (lostRatio <= 0 || lostRatio > 3) {
            throw new BizException("丢失赔偿比例必须在0到3之间");
        }

        // 查找用户是否有该图书的借阅记录
        Integer recordId = findUserBookBorrowRecord(userId, bookId);

        // 检查是否已有丢失赔偿记录 - 使用long接收
        long existingCount = countExistingFee(userId, recordId, "loss_fee");
        if (existingCount > 0) {
            // 已有记录，返回该记录信息
            LambdaQueryWrapper<FeeRecord> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(FeeRecord::getUserId, userId)
                    .eq(FeeRecord::getFeeType, "loss_fee")
                    .orderByDesc(FeeRecord::getCreateTime)
                    .last("LIMIT 1");

            // 如果有借阅记录ID，添加到查询条件中
            if (recordId != null) {
                wrapper.eq(FeeRecord::getRecordId, recordId);
            } else {
                wrapper.isNull(FeeRecord::getRecordId);
            }

            FeeRecord existingRecord = feeRecordMapper.selectOne(wrapper);

            // 增加空指针检查
            if (existingRecord == null) {
                throw new BizException("系统检测到已有赔偿记录，但无法获取详情，请联系管理员");
            }

            FeeVO feeVO = createLostFeeVO(user, book, lostRatio, existingRecord.getAmount());
            feeVO.setFeeId(existingRecord.getFeeId());
            return feeVO;
        }

        // 计算丢失赔偿费用
        BigDecimal lostFee = book.getPrice().multiply(new BigDecimal(lostRatio))
                .setScale(2, RoundingMode.HALF_UP);

        // 创建丢失赔偿记录
        FeeRecord feeRecord = new FeeRecord();
        feeRecord.setUserId(userId);
        feeRecord.setRecordId(recordId);
        feeRecord.setFeeType("loss_fee");
        feeRecord.setAmount(lostFee);
        feeRecord.setStatus("unpaid");
        feeRecord.setCreateTime(LocalDateTime.now());
        feeRecord.setRemark(String.format("用户%d丢失《%s》，按%.2f比例赔偿",
                userId, book.getBookName(), lostRatio));

        feeRecordMapper.insert(feeRecord);

        // 构建并返回结果
        FeeVO feeVO = createLostFeeVO(user, book, lostRatio, lostFee);
        feeVO.setFeeId(feeRecord.getFeeId());

        return feeVO;
    }

    /**
     * 检查是否存在特定类型的费用记录
     * 返回值改为long类型，匹配selectCount的返回类型
     */
    private long countExistingFee(Integer userId, Integer recordId, String feeType) {
        LambdaQueryWrapper<FeeRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FeeRecord::getUserId, userId)
                .eq(FeeRecord::getFeeType, feeType)
                .ne(FeeRecord::getStatus, "refunded"); // 排除已退款的记录

        // 根据recordId是否为null设置不同条件
        if (recordId != null) {
            wrapper.eq(FeeRecord::getRecordId, recordId);
        } else {
            wrapper.isNull(FeeRecord::getRecordId);
        }

        // MyBatis-Plus的selectCount返回Long类型
        return feeRecordMapper.selectCount(wrapper);
    }

    /**
     * 创建逾期罚款记录
     */
    private void createOverdueFeeRecord(User user, BorrowRecord borrow, long days, BigDecimal amount) {
        // 查询图书信息
        Book book = bookMapper.selectById(borrow.getItemId());
        String bookName = book != null ? book.getBookName() : "未知图书";

        // 创建费用记录
        FeeRecord feeRecord = new FeeRecord();
        feeRecord.setUserId(user.getUserId());
        feeRecord.setRecordId(borrow.getRecordId());
        feeRecord.setFeeType("overdue_fee");
        feeRecord.setAmount(amount.setScale(2, RoundingMode.HALF_UP));
        feeRecord.setStatus("unpaid");
        feeRecord.setCreateTime(LocalDateTime.now());
        feeRecord.setRemark(String.format("《%s》逾期%d天产生的费用", bookName, days));

        feeRecordMapper.insert(feeRecord);
    }

    /**
     * 查找用户是否有该图书的借阅记录
     */
    private Integer findUserBookBorrowRecord(Integer userId, Integer bookId) {
        LambdaQueryWrapper<BorrowRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BorrowRecord::getUserId, userId)
                .eq(BorrowRecord::getItemId, bookId)
                .in(BorrowRecord::getStatus, "borrowing", "overdue")
                .orderByDesc(BorrowRecord::getBorrowDate)
                .last("LIMIT 1");

        BorrowRecord borrowRecord = borrowRecordMapper.selectOne(wrapper);
        return borrowRecord != null ? borrowRecord.getRecordId() : null;
    }

    /**
     * 创建损坏赔偿的VO对象
     */
    private FeeVO createDamageFeeVO(User user, Book book, double ratio, BigDecimal amount) {
        FeeVO feeVO = new FeeVO();
        feeVO.setUserId(user.getUserId());
        feeVO.setUserName(user.getUsername());
        feeVO.setBookId(book.getBookId());
        feeVO.setBookName(book.getBookName());
        feeVO.setType("damage_fee");
        feeVO.setTypeDesc("损坏赔偿");
        feeVO.setAmount(amount);
        feeVO.setRatio(ratio);
        feeVO.setCalculateTime(LocalDateTime.now());
        return feeVO;
    }

    /**
     * 创建丢失赔偿的VO对象
     */
    private FeeVO createLostFeeVO(User user, Book book, double ratio, BigDecimal amount) {
        FeeVO feeVO = new FeeVO();
        feeVO.setUserId(user.getUserId());
        feeVO.setUserName(user.getUsername());
        feeVO.setBookId(book.getBookId());
        feeVO.setBookName(book.getBookName());
        feeVO.setType("loss_fee");
        feeVO.setTypeDesc("丢失赔偿");
        feeVO.setAmount(amount);
        feeVO.setRatio(ratio);
        feeVO.setCalculateTime(LocalDateTime.now());
        return feeVO;
    }

    /**
     * 分页获取用户费用记录
     */
    @Override
    public IPage<FeeRecordVO> getUserFeeRecords(Integer userId, Integer page, Integer size, String feeType, String status) {
        // 构建查询条件
        LambdaQueryWrapper<FeeRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FeeRecord::getUserId, userId);
        
        if (feeType != null && !feeType.isEmpty()) {
            queryWrapper.eq(FeeRecord::getFeeType, feeType);
        }
        
        if (status != null && !status.isEmpty()) {
            queryWrapper.eq(FeeRecord::getStatus, status);
        }
        
        queryWrapper.orderByDesc(FeeRecord::getCreateTime);
        
        // 分页查询
        Page<FeeRecord> feeRecordPage = new Page<>(page, size);
        Page<FeeRecord> resultPage = feeRecordMapper.selectPage(feeRecordPage, queryWrapper);
        
        // 转换为VO
        List<FeeRecordVO> feeRecordVOList = resultPage.getRecords().stream()
                .map(this::convertToFeeRecordVO)
                .collect(Collectors.toList());
        
        // 构建返回结果
        Page<FeeRecordVO> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
        voPage.setRecords(feeRecordVOList);
        
        return voPage;
    }

    /**
     * 获取用户费用统计
     */
    @Override
    public FeeStatisticsVO getUserFeeStatistics(Integer userId) {
        FeeStatisticsVO statistics = new FeeStatisticsVO();
        
        // 查询待缴费用
        LambdaQueryWrapper<FeeRecord> unpaidWrapper = new LambdaQueryWrapper<>();
        unpaidWrapper.eq(FeeRecord::getUserId, userId)
                .eq(FeeRecord::getStatus, "unpaid");
        List<FeeRecord> unpaidFees = feeRecordMapper.selectList(unpaidWrapper);
        
        double unpaidAmount = unpaidFees.stream()
                .mapToDouble(fee -> fee.getAmount() != null ? fee.getAmount().doubleValue() : 0.0)
                .sum();
        statistics.setUnpaidAmount(unpaidAmount);
        statistics.setUnpaidCount(unpaidFees.size());
        
        // 查询已缴费用
        LambdaQueryWrapper<FeeRecord> paidWrapper = new LambdaQueryWrapper<>();
        paidWrapper.eq(FeeRecord::getUserId, userId)
                .eq(FeeRecord::getStatus, "paid");
        List<FeeRecord> paidFees = feeRecordMapper.selectList(paidWrapper);
        
        double paidAmount = paidFees.stream()
                .mapToDouble(fee -> fee.getAmount() != null ? fee.getAmount().doubleValue() : 0.0)
                .sum();
        statistics.setPaidAmount(paidAmount);
        statistics.setPaidCount(paidFees.size());
        
        // 计算总计
        statistics.setTotalAmount(unpaidAmount + paidAmount);
        statistics.setTotalCount(unpaidFees.size() + paidFees.size());
        
        return statistics;
    }

    /**
     * 支付费用
     */
    @Override
    @Transactional
    public boolean payFee(Integer feeId, String payMethod) {
        FeeRecord feeRecord = feeRecordMapper.selectById(feeId);
        if (feeRecord == null) {
            throw new BizException("费用记录不存在");
        }
        
        if ("paid".equals(feeRecord.getStatus())) {
            throw new BizException("该费用已支付");
        }
        
        // 更新费用记录状态
        feeRecord.setStatus("paid");
        feeRecord.setPayTime(LocalDateTime.now());
        feeRecord.setRemark(feeRecord.getRemark() + " - 支付方式: " + payMethod);
        
        return feeRecordMapper.updateById(feeRecord) > 0;
    }

    /**
     * 转换FeeRecord为FeeRecordVO
     */
    private FeeRecordVO convertToFeeRecordVO(FeeRecord feeRecord) {
        FeeRecordVO vo = new FeeRecordVO();
        vo.setFeeId(feeRecord.getFeeId());
        vo.setUserId(feeRecord.getUserId());
        vo.setRecordId(feeRecord.getRecordId());
        vo.setFeeType(feeRecord.getFeeType());
        vo.setAmount(feeRecord.getAmount());
        vo.setStatus(feeRecord.getStatus());
        vo.setCreateTime(feeRecord.getCreateTime());
        vo.setPayTime(feeRecord.getPayTime());
        vo.setRemark(feeRecord.getRemark());
        
        // 获取用户信息
        User user = userMapper.selectById(feeRecord.getUserId());
        if (user != null) {
            vo.setUsername(user.getUsername());
            vo.setRealName(user.getRealName());
        }
        
        // 获取图书信息（通过借阅记录）
        if (feeRecord.getRecordId() != null) {
            BorrowRecord borrowRecord = borrowRecordMapper.selectById(feeRecord.getRecordId());
            if (borrowRecord != null) {
                Book book = bookMapper.selectById(borrowRecord.getItemId());
                if (book != null) {
                    vo.setBookId(book.getBookId());
                    vo.setBookName(book.getBookName());
                    vo.setAuthor(book.getAuthor());
                }
            }
        }
        
        return vo;
    }
}
